x86 mca: Add MCE broadcast checkiing.
authorKeir Fraser <keir.fraser@citrix.com>
Fri, 29 Jan 2010 06:49:42 +0000 (06:49 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Fri, 29 Jan 2010 06:49:42 +0000 (06:49 +0000)
Some platform will broadcast MCE to all logical processor, while some
platform will not. Distinguish these platforms will be helpful for
unified MCA handler.

the "mce_fb" is a option to emulate the broadcast MCA in non-broadcast
platform. This is mainly for MCA software trigger.

Signed-off-by: Jiang, Yunhong <yunhong.jiang@intel.com>
xen/arch/x86/cpu/mcheck/mce.c
xen/arch/x86/cpu/mcheck/mce.h
xen/arch/x86/cpu/mcheck/mce_intel.c

index fdf56de6894781b378b84d24e63269e42b71c874..415e6a0a449514a87005eea676ed871c649fdaab 100644 (file)
 
 int mce_disabled;
 invbool_param("mce", mce_disabled);
-
+static int mce_force_broadcast;
+boolean_param("mce_fb", mce_force_broadcast);
 int is_mc_panic;
 unsigned int nr_mce_banks;
 
+int mce_broadcast = 0;
 static uint64_t g_mcg_cap;
 
 /* Real value in physical CTL MSR */
@@ -588,6 +590,21 @@ int mce_available(struct cpuinfo_x86 *c)
        return cpu_has(c, X86_FEATURE_MCE) && cpu_has(c, X86_FEATURE_MCA);
 }
 
+static int mce_is_broadcast(struct cpuinfo_x86 *c)
+{
+    if (mce_force_broadcast)
+        return 1;
+
+    /* According to Intel SDM Dec, 2009, 15.10.4.1, For processors with
+     * DisplayFamily_DisplayModel encoding of 06H_EH and above,
+     * a MCA signal is broadcast to all logical processors in the system
+     */
+    if (c->x86_vendor == X86_VENDOR_INTEL && c->x86 == 6 &&
+        c->x86_model >= 0xe)
+            return 1;
+    return 0;
+}
+
 /*
  * Check if bank 0 is usable for MCE. It isn't for AMD K7,
  * and Intel P6 family before model 0x1a.
@@ -608,13 +625,24 @@ int mce_firstbank(struct cpuinfo_x86 *c)
 /* This has to be run for each processor */
 void mcheck_init(struct cpuinfo_x86 *c)
 {
-       int inited = 0, i;
+       int inited = 0, i, broadcast;
+    static int broadcast_check;
 
        if (mce_disabled == 1) {
-               printk(XENLOG_INFO "MCE support disabled by bootparam\n");
+               dprintk(XENLOG_INFO, "MCE support disabled by bootparam\n");
                return;
        }
 
+    broadcast = mce_is_broadcast(c);
+    if (broadcast_check && (broadcast != mce_broadcast) )
+            dprintk(XENLOG_INFO,
+                "CPUs have mixed broadcast support"
+                "may cause undetermined result!!!\n");
+
+    broadcast_check = 1;
+    if (broadcast)
+        mce_broadcast = broadcast;
+
        for (i = 0; i < MAX_NR_BANKS; i++)
                set_bit(i,mca_allbanks);
 
@@ -1542,14 +1570,17 @@ long do_mca(XEN_GUEST_HANDLE(xen_mc_t) u_xen_mc)
 
                if (target >= NR_CPUS)
                        return x86_mcerr("do_mca #MC: bad target", -EINVAL);
-                      
+
                if (!cpu_isset(target, cpu_online_map))
                        return x86_mcerr("do_mca #MC: target offline", -EINVAL);
 
                add_taint(TAINT_ERROR_INJECT);
 
-               on_selected_cpus(cpumask_of(target), x86_mc_mceinject,
-                                mc_mceinject, 1);
+        if ( mce_broadcast )
+            on_each_cpu(x86_mc_mceinject, mc_mceinject, 0);
+        else
+            on_selected_cpus(cpumask_of(target), x86_mc_mceinject,
+                  mc_mceinject, 1);
                break;
 
        default:
index 47c8852001fbb62855e1cd6cec1150f3eff3e949..48fdf506d8299d488aaa1e5b33e682f50a523322 100644 (file)
@@ -121,6 +121,7 @@ DECLARE_PER_CPU(cpu_banks_t, no_cmci_banks);
 extern int cmci_support;
 extern int ser_support;
 extern int is_mc_panic;
+extern int mce_broadcast;
 extern void mcheck_mca_clearbanks(cpu_banks_t);
 
 extern mctelem_cookie_t mcheck_mca_logout(enum mca_source, cpu_banks_t,
index e8f95e20541b0d92fd9da141adb48c699d8d6565..fe1610d426f37ceca6841928f9eb9056455dc517 100644 (file)
@@ -612,6 +612,8 @@ static void mce_barrier_enter(struct mce_softirq_barrier *bar)
 {
       int gen;
 
+      if (!mce_broadcast)
+          return;
       atomic_inc(&bar->ingen);
       gen = atomic_read(&bar->outgen);
       mb();
@@ -627,6 +629,8 @@ static void mce_barrier_exit(struct mce_softirq_barrier *bar)
 {
       int gen;
 
+      if (!mce_broadcast)
+          return;
       atomic_inc(&bar->outgen);
       gen = atomic_read(&bar->ingen);
       mb();